/**
 * 责任链模式：将所有请求的处理者通过前一对象记住下一个对象的引用而形成一条链，当有请求发生时，可以沿着这条链进行传递，直到有对象处理为止。
 * 责任链模式适合应用场景：
 * 1. 当程序需要使用不同方式处理不同种类请求，而且请求类型和顺序预先未知时，可以使用责任链模式。该模式能将多个处理者连接成一条链。 接收到请求后， 它会 “询问” 每个处理者是否能够对其进行处理。 这样所有处理者都有机会来处理请求。
 * 2. 当必须按顺序执行多个处理者时，可以使用该模式。无论以何种顺序将处理者连接成一条链，所有请求都会严格按照顺序通过链上的处理者。
 * 优点：
 * 1. 单一职责原则。可对发起操作和执行操作的类进行解耦。
 * 2. 开闭原则。可以在不更改现有代码的情况下在程序中新增处理者。
 */
#pragma once

#include <iostream>
#include <string>
#include <memory>
using namespace std;

namespace chainofresponsibility
{
//抽象管理者
class Manager
{
public:
    Manager(Manager *manager, const string& name) : m_manager(manager), m_name(name) {}
    virtual void DealWithRequest(const string& name, int num) {}

protected:
    shared_ptr<Manager> m_manager;
    string m_name;
};

//项目经理
class ProjectManager : public Manager
{
public:
    ProjectManager(Manager* manager, const string& name) : Manager(manager, name) {}
    void DealWithRequest(const string& name, int num) override {
        if (num < 500) { //项目经理职权之内
            cout << "PM:" << m_name << " agree staff:" << name << " raise " << num << " rmb." << endl;
        } else {
            cout << "PM:" << m_name << " no authority to deal with" << endl;
            m_manager->DealWithRequest(name, num);
        }
    }
};
//部门经理
class DepartmentManager : public Manager
{
public:
    DepartmentManager(Manager* manager, const string& name) : Manager(manager, name) {}
    void DealWithRequest(const string& name, int num) override {
        if (num < 1000) { //部门经理职权之内
            cout << "DM:" << m_name << " agree staff:" << name << " raise " << num << " rmb." << endl;
        } else {
            cout << "DM:" << m_name << " no authority to deal with" << endl;
            m_manager->DealWithRequest(name, num);
        }
    }
};
//部门主管
class DepartmentSupervisor : public Manager
{
public:
    DepartmentSupervisor(Manager* manager, const string& name) :Manager(manager, name) {}
    void DealWithRequest(const string& name, int num) override { //部门主管可以处理所有请求
        cout << "DS:" << m_name << " agree staff:" << name << " raise " << num << " rmb." << endl;
    }
};

void ClientCode()
{
    Manager* ds = new DepartmentSupervisor(nullptr, "A"); //设置上级，部门主管没有上级
	Manager* dm = new DepartmentManager(ds, "B"); //设置上级
	Manager* pm = new ProjectManager(dm, "C"); //设置上级
	pm->DealWithRequest("D", 300); //员工D要求加薪
	pm->DealWithRequest("E", 600);
	pm->DealWithRequest("F", 1000);
    delete ds;
}
} // namespace chainofresponsibility
